const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

class MyPromise {
  #state = PENDING; // 状态
  #reason = undefined; // 运行结果

  #thenArr = []; // 存放then回调函数
  constructor(taskFn) {
    // 成功回调
    const resolve = (reason) => {
      this.#changeState(FULFILLED, reason)
    }

    // 失败回调
    const reject = (reason) => {
      this.#changeState(REJECTED, reason)
    }
    try {
      taskFn(resolve, reject)
    } catch(err) {
      reject(err)
    }
  }

  // 状态变更后 执行回调
  #changeState(state, reason) {
    if(this.#state !== PENDING) return;
    this.#state = state;
    this.#reason = reason;
    this.#runThen() // 执行then回调
  }

  // 是否是 Promise 函数
  #isPromise(value) {
    if(value !== null && (typeof value === 'object' || typeof value === 'function')) {
      if(typeof then === 'function') {
        return true;
      }
    }
    return false;
  }

  // 将方法放入微队列
  #runMicroTask(fn) {
    if(typeof queueMicrotask === 'function') {
      queueMicrotask(fn) 
    } else if(typeof MutationObserver === 'function') {
      const observer = new MutationObserver(fn);
      const textNode = document.createTextNode('1');
      observer.observe(textNode, { characterData: true });
      textNode.textContent = '2';
    } else if(typeof process === 'object' && typeof process.nextTick === 'function') {
      return process.nextTick(fn)
    } else {
      setTimeout(fn, 0)
    }
  }

  #runOne(callback, resolve, reject) {
    this.#runMicroTask(() => { // 放入微队列中执行 保证then方法执行顺序
      if(typeof callback !== 'function') {
        const current = this.#state === FULFILLED ? resolve:reject;
        current(this.#reason)
        return
      }
      try {
        const result = callback(this.#reason)
        if(this.#isPromise(result)) {
          result.then(resolve, reject) 
        } else {
          resolve(result)
        }
      } catch(err) {
        reject(err)
      }
    })
  }

  #runThen() {
    if(this.#state === PENDING) return; // 状态未变更 不执行回调
    while (this.#thenArr.length > 0) {
      const { onFulfilled, onReject, resolve, reject } = this.#thenArr.shift();
      if(this.#state === FULFILLED) {
        this.#runOne(onFulfilled, resolve, reject)
      } else {
        this.#runOne(onReject, resolve, reject)
      }
    }
  }

  // then 调用的时候将回调函数放入队列中
  then(onFulfilled, onReject) {
    return new MyPromise((resolve, reject) => {
      this.#thenArr.push({
        onFulfilled,
        onReject,
        resolve,
        reject
      })
      this.#runThen()
    })
    
  }
}

export { MyPromise }